use actix_web::{HttpResponse, error, http, web, ResponseError};
use serde::{Serialize, Deserialize};
use failure::Fail;
use actix_web::http::StatusCode;
use actix_web::body::Body;


pub mod school;
pub mod user;
pub mod course_type;
pub mod course;
pub mod resource;
pub mod code;

pub type Res = HttpResponse;

#[derive(Fail, Debug)]
pub enum BusinessError {
    #[fail(display = "{}", msg)]
    ValidationError { msg: String },
    #[fail(display = "未登录或登录过期，请重新登陆后再访问。")]
    Unauthorized,
    #[fail(display = "您权限不足。")]
    Forbidden,
    #[fail(display = "您要获取的资源不存在。")]
    NotFound,
    #[fail(display = "服务器出错，请稍后再访问，或联系网站管理员微信:173126019。")]
    InternalError,
}

#[derive(Serialize)]
pub struct Err {
    msg: String,
}


// 这里用于在 api 层直接可以返回 BusinessError ，自动转换成 HttpResponse
impl Into<HttpResponse> for BusinessError {
    fn into(self) -> Res {
        let mut res = match self {
            BusinessError::ValidationError { .. } => { HttpResponse::BadRequest() }
            BusinessError::Unauthorized => { HttpResponse::Unauthorized() }
            BusinessError::Forbidden => { HttpResponse::Forbidden() }
            BusinessError::NotFound => { HttpResponse::NotFound() }
            BusinessError::InternalError => { HttpResponse::InternalServerError() }
        };
        res.json(Err { msg: self.to_string() })
    }
}

#[derive(Deserialize, Serialize)]
pub struct Data<T> where T: Serialize {
    data: T,
}

impl<T: Serialize> Data<T> {
    pub fn ok(data: T) -> Self {
        Data { data }
    }

    pub fn to_json(&self) -> Res {
        HttpResponse::Ok()
            .set_header(http::header::CONTENT_TYPE, "application/json; charset=utf-8")
            .json(&self.data)
    }
}


pub fn routes(cfg: &mut web::ServiceConfig) {
    cfg.service(
        web::scope("/api")
            .service(user::create_user)
            .service(user::get_user_info)
            .service(user::create_token)
            .service(user::test)
    ).service(actix_files::Files::new(
        "/statics",
        "/",
    ))
        .route("/1", web::get().to(|| {
            HttpResponse::Ok().body("Hello")
        }));
}